use std::fmt::Write;
use std::path::PathBuf;
use std::process::{Command, Stdio};

#[derive(Default, Debug)]
pub(crate) struct RustcTargets {
    /// Targets with host tool artifacts.
    pub(crate) hosts: Vec<String>,

    /// All targets we distribute some artifacts for (superset of `hosts`).
    pub(crate) targets: Vec<String>,
}

fn collect_rustc_targets() -> RustcTargets {
    let rustc_path = std::env::var("RUSTC").expect("RUSTC set");
    let output = Command::new(&rustc_path)
        .arg("--print=all-target-specs-json")
        .env("RUSTC_BOOTSTRAP", "1")
        .arg("-Zunstable-options")
        .stderr(Stdio::inherit())
        .output()
        .unwrap();
    assert!(output.status.success());
    let json: serde_json::Value = serde_json::from_slice(&output.stdout).unwrap();

    let mut rustc_targets = RustcTargets::default();
    for (target, json) in json.as_object().unwrap().iter() {
        let Some(tier) = json["metadata"]["tier"].as_u64() else {
            eprintln!("skipping {target}: no tier in metadata");
            continue;
        };
        let host_tools: Option<bool> =
            serde_json::from_value(json["metadata"]["host_tools"].clone()).unwrap();

        if !(tier == 1 || tier == 2) {
            eprintln!("ignoring {target}: tier {tier} insufficient for target to be in manifest");
            continue;
        }

        if host_tools == Some(true) {
            rustc_targets.hosts.push(target.to_owned());
            rustc_targets.targets.push(target.to_owned());
        } else {
            rustc_targets.targets.push(target.to_owned());
        }
    }

    rustc_targets
}

fn main() {
    let targets = collect_rustc_targets();

    // Verify we ended up with a reasonable target list.
    assert!(targets.hosts.len() >= 10);
    assert!(targets.targets.len() >= 30);
    assert!(targets.hosts.iter().any(|e| e == "x86_64-unknown-linux-gnu"));
    assert!(targets.targets.iter().any(|e| e == "x86_64-unknown-linux-gnu"));

    let mut output = String::new();

    writeln!(output, "static HOSTS: &[&str] = &[").unwrap();
    for host in &targets.hosts {
        writeln!(output, "    {:?},", host).unwrap();
    }
    writeln!(output, "];").unwrap();

    writeln!(output, "static TARGETS: &[&str] = &[").unwrap();
    for target in targets.targets {
        writeln!(output, "    {:?},", target).unwrap();
    }
    writeln!(output, "];").unwrap();

    writeln!(output, "static MSI_INSTALLERS: &[&str] = &[").unwrap();
    for host in &targets.hosts {
        if host.contains("-windows-") {
            writeln!(output, "    {:?},", host).unwrap();
        }
    }
    writeln!(output, "];").unwrap();

    writeln!(output, "static MINGW: &[&str] = &[").unwrap();
    for host in targets.hosts {
        if host.contains("-windows-gnu") {
            writeln!(output, "    {:?},", host).unwrap();
        }
    }
    writeln!(output, "];").unwrap();

    std::fs::write(PathBuf::from(std::env::var_os("OUT_DIR").unwrap()).join("targets.rs"), output)
        .unwrap();
}
